from keras.datasets import imdb

# -------------------------------------下载或者准备训练数据集-----------------------
# 参数 num_words=10000 的意思是仅保留训练数据中前 10 000 个最常出现的单词。
# 低频单词将被舍弃。这样得到的向量数据不会太大，便于处理。
# train_data 和 test_data 这两个变量都是评论组成的列表，每条评论又是单词索引组成
# 的列表（表示一系列单词）。 train_labels 和 test_labels 都是 0 和 1 组成的列表，其中 0
# 代表负面（negative）， 1 代表正面（positive）
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
# 测试查看一下
# print(train_data[0])
# [1, 14, 22, 16, 43, 530, 973, 1622, 1385, 65, 458, 4468, 66, 3941, 4, 173, 36, 256, 5, 25, 100, 43, 838, 112, 50, 670, 2, 9, 35, 480, 284, 5, 150, 4, 172, 112, 167, 2, 336, 385, 39, 4, 172, 4536, 1111, 17, 546, 38, 13, 447, 4, 192, 50, 16, 6, 147, 2025, 19, 14, 22, 4, 1920, 4613, 469, 4, 22, 71, 87, 12, 16, 43, 530, 38, 76, 15, 13, 1247, 4, 22, 17, 515, 17, 12, 16, 626, 18, 2, 5, 62, 386, 12, 8, 316, 8, 106, 5, 4, 2223, 5244, 16, 480, 66, 3785, 33, 4, 130, 12, 16, 38, 619, 5, 25, 124, 51, 36, 135, 48, 25, 1415, 33, 6, 22, 12, 215, 28, 77, 52, 5, 14, 407, 16, 82, 2, 8, 4, 107, 117, 5952, 15, 256, 4, 2, 7, 3766, 5, 723, 36, 71, 43, 530, 476, 26, 400, 317, 46, 7, 4, 2, 1029, 13, 104, 88, 4, 381, 15, 297, 98, 32, 2071, 56, 26, 141, 6, 194, 7486, 18, 4, 226, 22, 21, 134, 476, 26, 480, 5, 144, 30, 5535, 18, 51, 36, 28, 224, 92, 25, 104, 4, 226, 65, 16, 38, 1334, 88, 12, 16, 283, 5, 16, 4472, 113, 103, 32, 15, 16, 5345, 19, 178, 32]
# print(train_labels[0])  # 1
# 由于限定为前 10 000 个最常见的单词，单词索引都不会超过 10 000。
# print(max([max(sequence) for sequence in train_data]))  # 9999
# 你可以将某条评论迅速解码为英文单词。
# word_index = imdb.get_word_index()
# reverse_word_index = dict(
#     [(value, key) for (key, value) in word_index.items()])
# decoded_review = ' '.join(
#     [reverse_word_index.get(i - 3, '?') for i in train_data[0]])

# -------------------------------------准备数据-----------------------
# 你不能将整数序列直接输入神经网络。你需要将列表转换为张量。转换方法有以下两种。
# 一、填充列表，使其具有相同的长度，再将列表转换成形状为 (samples, word_indices)
# 的整数张量，然后网络第一层使用能处理这种整数张量的层（即 Embedding 层，本书
# 后面会详细介绍）。

# 二、对列表进行 one-hot 编码，将其转换为 0 和 1 组成的向量。举个例子，序列 [3, 5] 将会
# 被转换为 10 000 维向量，只有索引为 3 和 5 的元素是 1，其余元素都是 0。然后网络第
# 一层可以用 Dense 层，它能够处理浮点数向量数据。


# 将整数序列编码为二进制矩阵
import numpy as np


def vectorize_sequences(sequences, dimension=10000):
    results = np.zeros((len(sequences), dimension))  # 创建一个形状为(len(sequences),dimension) 的零矩阵
    for i, sequence in enumerate(sequences):
        results[i, sequence] = 1.  # 将 results[i] 的指定索引设为 1
    return results


x_train = vectorize_sequences(train_data)  # 将训练数据向量化
x_test = vectorize_sequences(test_data)  # 将测试数据向量化
# print(x_train)  # 25000
# print(x_train[0])  # [ 0.  1.  1. ...,  0.  0.  0.]
# print(x_test)  # 25000
# print(x_test[0])  # [ 0.  1.  1. ...,  0.  0.  0.]
#
# 你还应该将标签向量化，这很简单。
y_train = np.asarray(train_labels).astype('float32')
y_test = np.asarray(test_labels).astype('float32')

# -------------------------------------模型定义-----------------------
from keras import models
from keras import layers
from keras import regularizers

model = models.Sequential()
model.add(layers.Dense(16, kernel_regularizer=regularizers.l1(0.001),
                       activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, kernel_regularizer=regularizers.l1(0.001), activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))

# -------------------------------------编译模型-----------------------
# from keras import optimizers

model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['acc'])

# 使用自定义的损失和指标(如果需要的话)
# from keras import losses
# from keras import metrics
# model.compile(optimizer=optimizers.RMSprop(lr=0.001),
# loss=losses.binary_crossentropy,
# metrics=[metrics.binary_accuracy])

# -------------------------------------验证你的方法-----------------------
# 为了在训练过程中监控模型在前所未见的数据上的精度，你需要将原始训练数据留出 10 000
# 个样本作为验证集。
x_val = x_train[:10000]
partial_x_train = x_train[10000:]
y_val = y_train[:10000]
partial_y_train = y_train[10000:]

# -------------------------------------训练模型-----------------------
model.fit(x_train, y_train, epochs=4, batch_size=512)
# -------------------------------------测试评估-----------------------
results = model.evaluate(x_test, y_test)

print(results)  # [0.54948849891662599, 0.86780000000000002]
